package controllers

import (
	"fmt"
	"github.com/astaxie/beego"
	"io"
	"net"
	"servermg/log"
	"servermg/models"
	"servermg/protocol"
	"time"
)

const (
	CMD_SET_SERVER_RETIRED   = 0x0905
	CMD_CHECK_SERVER_STATUS  = 0x0906
	CMD_SET_SERVER_AUTO_EXIT = 0x0907
)

var (
	AllocsAddr []string
	Allocs     map[int32]*models.Alloc
)

type RetireController struct {
	beego.Controller
}

func (c *RetireController) Retire() {
	log.Debug("Retire")
	level, _ := c.GetInt("level")
	port, _ := c.GetInt("port")
	svid, _ := c.GetInt("svid")
	flag, _ := c.GetInt("flag")
	log.Notice("server level[%d],svid[%d],port[%d],flag[%d]", level, svid, port, flag)

	retireGameServer(int32(level), int32(svid), int32(flag))

	c.Redirect("/retire/status", 301)
	return

}
func retireGameServer(level, svid, flag int32) int32 {
	alloc := Allocs[level]
	if alloc != nil {
		for _, game := range alloc.GameServer {
			if game.ServerID == svid {
				log.Debug("retire:", svid)
				log.Debug("Alloc addr = %s", alloc.Addr)
				tcpAddr, err := net.ResolveTCPAddr("tcp4", alloc.Addr)
				CheckError(err)
				conn, err := net.DialTCP("tcp", nil, tcpAddr)
				CheckError(err)

				defer conn.Close()
				pkg := &protocol.BoyaaPacket{}
				pkg.WriteBeginQE1(CMD_SET_SERVER_RETIRED)
				pkg.WriteShort(int16(1))
				pkg.WriteShort(int16(svid))
				pkg.WriteShort(int16(flag))
				pkg.WriteEnd()

				SendPacket(pkg, conn)

				result := Receiver(conn)
				ret := result.ReadInt()
				log.Debug("retire game server[%d] result[%d]", svid, ret)
				return ret

			}
		}
	}

	return 1
}

func (c *RetireController) Status() {

	log.Debug("Status")
	allocs := make([]models.Alloc, 0, 9)
	addrs := AllocsAddr
	for _, addr := range addrs {
		packet := getInfo(addr)
		alloc := parseInfo(packet)
		alloc.Addr = addr
		allocs = append(allocs, *alloc)
		Allocs[alloc.Level] = alloc
	}
	log.Debug("allocs len[%d] cap[%d] \n", len(allocs), cap(allocs))
	c.Data["Allocs"] = allocs
	c.TplName = "retire_info.tpl"
}

func parseInfo(pkg *protocol.BoyaaPacket) *models.Alloc {
	alloc := &models.Alloc{}
	level := pkg.ReadInt()
	alloc.Level = level
	ver := pkg.ReadInt()
	count := pkg.ReadInt()
	log.Debug("level[%d],ver[%d],count[%d]", level, ver, count)
	for i := 0; i < int(count); i++ {
		game_info := &models.GameInfo{}
		server_id := pkg.ReadInt()
		port := pkg.ReadInt()
		retire := pkg.ReadInt()
		user_count := pkg.ReadInt()
		table_count := pkg.ReadInt()
		creat_time := pkg.ReadInt()
		auto_exit := pkg.ReadInt()
		log.Debug("server_id[%d],port[%d],retire[%d],user_count[%d],table_count[%d],create_time[%d],auto_exit[%d]\n", server_id, port, retire, user_count, table_count, creat_time, auto_exit)
		game_info.ServerID = server_id
		game_info.Port = port
		game_info.Retire = (retire > 0)
		game_info.UserCount = user_count
		game_info.TableCount = table_count
		game_info.CreateTime = time.Unix(int64(creat_time), 0).Format("2006年01月02日 15:04:05")
		game_info.AutoExit = (auto_exit > 0)
		alloc.GameServer = append(alloc.GameServer, game_info)
	}
	alloc.Count = int32(len(alloc.GameServer))

	return alloc
}

func getInfo(addr string) *protocol.BoyaaPacket {
	//server := "192.168.100.157:7011"
	tcpAddr, err := net.ResolveTCPAddr("tcp4", addr)
	CheckError(err)

	conn, err := net.DialTCP("tcp", nil, tcpAddr)
	CheckError(err)

	defer conn.Close()
	pkg := new(protocol.BoyaaPacket)
	pkg.WriteBeginQE1(CMD_CHECK_SERVER_STATUS)
	pkg.WriteInt(7)
	pkg.WriteEnd()

	SendPacket(pkg, conn)

	return Receiver(conn)

}

func Receiver(conn net.Conn) *protocol.BoyaaPacket {
	buffer := make([]byte, 2048)

	n, err := conn.Read(buffer)
	switch err {
	case nil:
		return Decode(buffer[:n])
	case io.EOF:
		log.Debug("Warning: End of data: %s \n", err)
		return nil
	default:
		log.Debug("Error: Reading data: %s \n", err)
		return nil

	}

}

func Decode(buf []byte) *protocol.BoyaaPacket {
	pkg := new(protocol.BoyaaPacket)
	pkg.Packet(buf)

	return pkg
}

func SendPacket(packet *protocol.BoyaaPacket, conn net.Conn) {
	log.Debug("send packet :", packet.Data())
	conn.Write(packet.Data())
}

func CheckError(err error) {
	if err != nil {
		log.Debug("Fatal error: %s", err.Error())
	}
}

func init() {

	Allocs = make(map[int32]*models.Alloc)
	alloc_count, _ := beego.AppConfig.Int("alloc_count")
	for i := 0; i < alloc_count; i++ {
		key := fmt.Sprintf("alloc_%d", i)
		add := beego.AppConfig.String(key)
		AllocsAddr = append(AllocsAddr, add)
		fmt.Println(key, add)
	}
}
